Bug 339318 - Allow page rendering to (optionally) happen in a thread
authorMarek Kasik <mkasik@redhat.com>
Fri, 19 Dec 2008 16:42:05 +0000 (16:42 +0000)
committerMarek Kašík <mkasik@src.gnome.org>
Fri, 19 Dec 2008 16:42:05 +0000 (16:42 +0000)
2008-12-19  Marek Kasik  <mkasik@redhat.com>

Bug 339318 - Allow page rendering to (optionally) happen in a thread

* gtk/gtk.symbols: API change
* doc/reference/gtk/gtk-sections.txt: API change
* gtk/gtkprintoperation-private.h
* gtk/gtkprintoperation.h
* gtk/gtkprintoperation.c: Adds 2 new functions
   gtk_print_operation_set_defer_drawing()
     - Sets up the GtkPrintOperation to wait for calling of
       gtk_print_operation_draw_page_finish() from application. It can
       be used for drawing page in another thread.
       This function must be called in the callback of "draw-page"
       signal.
   gtk_print_operation_draw_page_finish()
     - Signalize that drawing of particular page is complete.
       It is called after completion of page drawing (e.g. drawing
       in another thread).
       If gtk_print_operation_set_defer_drawing() was called before,
       then this function has to be called by application. In another
       case it is called by the library itself.

svn path=/trunk/; revision=21913

ChangeLog
docs/reference/gtk/gtk-sections.txt
gtk/gtk.symbols
gtk/gtkprintoperation-private.h
gtk/gtkprintoperation.c
gtk/gtkprintoperation.h

index c1299be435c49c207e86f208cf6059aae6e089d0..4ddd51950154d265da2fe3f24c212d0da058fc49 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2008-12-19  Marek Kasik  <mkasik@redhat.com>
+
+       Bug 339318 - Allow page rendering to (optionally) happen in a thread
+
+       * gtk/gtk.symbols: API change
+       * doc/reference/gtk/gtk-sections.txt: API change
+       * gtk/gtkprintoperation-private.h
+       * gtk/gtkprintoperation.h
+       * gtk/gtkprintoperation.c: Adds 2 new functions
+          gtk_print_operation_set_defer_drawing()
+            - Sets up the GtkPrintOperation to wait for calling of
+              gtk_print_operation_draw_page_finish() from application. It can
+              be used for drawing page in another thread.
+              This function must be called in the callback of "draw-page"
+              signal.
+          gtk_print_operation_draw_page_finish()
+            - Signalize that drawing of particular page is complete.
+              It is called after completion of page drawing (e.g. drawing
+              in another thread).
+              If gtk_print_operation_set_defer_drawing() was called before,
+              then this function has to be called by application. In another
+              case it is called by the library itself.
+
 2008-12-15  Matthias Clasen  <mclasen@redhat.com>
 
         * gtk/gtkprintunixdialog.c: Don't export emit_ok_response
index 1ec1925d092a365f2bebc97aa67051c48f1c83d5..b49a731ea1f0dcf62a325c9735926c017ff38b40 100644 (file)
@@ -6454,6 +6454,8 @@ gtk_print_operation_set_track_print_status
 gtk_print_operation_set_custom_tab_label
 gtk_print_operation_run
 gtk_print_operation_cancel
+gtk_print_operation_draw_page_finish
+gtk_print_operation_set_defer_drawing
 gtk_print_operation_get_status
 gtk_print_operation_get_status_string
 gtk_print_operation_is_finished
index 39f32f35e7f77f56190774886fd9b8f7eee3e4d4..2b4f07fc479ca55a44105947119c830fefd73a4a 100644 (file)
@@ -2909,6 +2909,8 @@ gtk_print_operation_get_status
 gtk_print_operation_get_status_string
 gtk_print_operation_is_finished
 gtk_print_operation_cancel
+gtk_print_operation_draw_page_finish
+gtk_print_operation_set_defer_drawing
 #endif
 #endif
 
index 3595314b4df411a059080c2dd3d0438e0ef59f4c..0e5f606c80355f0a7e7013f1d65a2ec33e19c83c 100644 (file)
 
 G_BEGIN_DECLS
 
+/* Page drawing states */
+typedef enum
+{
+  GTK_PAGE_DRAWING_STATE_READY,
+  GTK_PAGE_DRAWING_STATE_DRAWING,
+  GTK_PAGE_DRAWING_STATE_DEFERRED_DRAWING
+} GtkPageDrawingState;
+
 struct _GtkPrintOperationPrivate
 {
   GtkPrintOperationAction action;
@@ -45,6 +53,8 @@ struct _GtkPrintOperationPrivate
   guint allow_async        : 1;
   guint is_sync            : 1;
 
+  GtkPageDrawingState      page_drawing_state;
+
   guint print_pages_idle_id;
   guint show_progress_timeout_id;
 
index 0362d58f316385bec1028fccc05b933258c92e95..403902403e3e545539e5e6867f9aadc90af68c1a 100644 (file)
@@ -160,6 +160,8 @@ gtk_print_operation_init (GtkPrintOperation *operation)
   priv->track_print_status = FALSE;
   priv->is_sync = FALSE;
 
+  priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_READY;
+
   priv->rloop = NULL;
   priv->unit = GTK_UNIT_PIXEL;
 
@@ -417,19 +419,31 @@ preview_print_idle (gpointer data)
   GtkPrintOperation *op;
   gboolean retval = TRUE;
   cairo_t *cr;
+  GtkPrintOperationPrivate *priv; 
 
   pop = (PreviewOp *) data;
   op = GTK_PRINT_OPERATION (pop->preview);
+  priv = op->priv;
 
-  gtk_print_operation_preview_render_page (pop->preview, pop->page_nr);
-  
-  cr = gtk_print_context_get_cairo_context (pop->print_context);
-  _gtk_print_operation_platform_backend_preview_end_page (op, pop->surface, cr);
-  
-  /* TODO: print out sheets not pages and follow ranges */
-  pop->page_nr++;
-  if (op->priv->nr_of_pages <= pop->page_nr)
-    retval = FALSE;
+
+  if (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_READY)
+    {
+      /* TODO: print out sheets not pages and follow ranges */
+      if (pop->page_nr >= op->priv->nr_of_pages)
+        retval = FALSE;
+
+      if (pop->page_nr > 0)
+        {
+          cr = gtk_print_context_get_cairo_context (pop->print_context);
+          _gtk_print_operation_platform_backend_preview_end_page (op, pop->surface, cr);
+        }
+
+      if (retval)
+        {
+          gtk_print_operation_preview_render_page (pop->preview, pop->page_nr);
+          pop->page_nr++;
+        }
+    }
 
   return retval;
 }
@@ -2046,6 +2060,64 @@ update_progress (PrintPagesData *data)
     }
  }
 
+/**
+ * gtk_print_operation_set_defer_drawing:
+ * @op: a #GtkPrintOperation
+ * 
+ * Sets up the #GtkPrintOperation to wait for calling of
+ * gtk_print_operation_draw_page_finish() from application. It can
+ * be used for drawing page in another thread.
+ *
+ * This function must be called in the callback of "draw-page" signal.
+ *
+ * Since: 2.16
+ **/
+void
+gtk_print_operation_set_defer_drawing (GtkPrintOperation *op)
+{
+  GtkPrintOperationPrivate *priv = op->priv;
+
+  g_return_if_fail (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_DRAWING);
+
+  priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_DEFERRED_DRAWING;
+}
+
+/**
+ * gtk_print_operation_draw_page_finish:
+ * @op: a #GtkPrintOperation
+ * 
+ * Signalize that drawing of particular page is complete.
+ *
+ * It is called after completion of page drawing (e.g. drawing in another
+ * thread).
+ * If gtk_print_operation_set_defer_drawing() was called before, then this function
+ * has to be called by application. In another case it is called by the library
+ * itself.
+ *
+ * Since: 2.16
+ **/
+void
+gtk_print_operation_draw_page_finish (GtkPrintOperation *op)
+{
+  GtkPrintOperationPrivate *priv = op->priv;
+  GtkPageSetup *page_setup;
+  GtkPrintContext *print_context;
+  cairo_t *cr;
+  
+  print_context = priv->print_context;
+  page_setup = gtk_print_context_get_page_setup (print_context);
+
+  cr = gtk_print_context_get_cairo_context (print_context);
+
+  priv->end_page (op, print_context);
+  
+  cairo_restore (cr);
+
+  g_object_unref (page_setup);
+
+  priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_READY;
+}
+
 static void
 common_render_page (GtkPrintOperation *op,
                    gint               page_nr)
@@ -2080,161 +2152,178 @@ common_render_page (GtkPrintOperation *op,
   if (!priv->use_full_page)
     _gtk_print_context_translate_into_margin (print_context);
   
+  priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_DRAWING;
+
   g_signal_emit (op, signals[DRAW_PAGE], 0, 
                 print_context, page_nr);
 
-  priv->end_page (op, print_context);
-  
-  cairo_restore (cr);
-
-  g_object_unref (page_setup);
+  if (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_DRAWING)
+    gtk_print_operation_draw_page_finish (op);
 }
 
-static gboolean
-print_pages_idle (gpointer user_data)
+void
+prepare_data (PrintPagesData *data)
 {
-  PrintPagesData *data; 
-  GtkPrintOperationPrivate *priv; 
-  GtkPageSetup *page_setup;
-  gboolean done = FALSE;
-  gint i;
+  GtkPrintOperationPrivate *priv;
+  GtkPageSetup             *page_setup;
+  gint                      i;
 
-  data = (PrintPagesData*)user_data;
   priv = data->op->priv;
 
-  if (priv->status == GTK_PRINT_STATUS_PREPARING)
+  if (!data->initialized)
     {
-      if (!data->initialized)
-       {
-         data->initialized = TRUE;
-         page_setup = create_page_setup (data->op);
-         _gtk_print_context_set_page_setup (priv->print_context, 
-                                            page_setup);
-         g_object_unref (page_setup);
-      
-         g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
-      
-         if (priv->manual_collation)
-           {
-             data->uncollated_copies = priv->manual_num_copies;
-             data->collated_copies = 1;
-           }
-         else
-           {
-             data->uncollated_copies = 1;
-             data->collated_copies = priv->manual_num_copies;
-           }
-
-         goto out;
-       }
-      
-      if (g_signal_has_handler_pending (data->op, signals[PAGINATE], 0, FALSE))
-       {
-         gboolean paginated = FALSE;
+      data->initialized = TRUE;
+      page_setup = create_page_setup (data->op);
+      _gtk_print_context_set_page_setup (priv->print_context, 
+                                 page_setup);
+      g_object_unref (page_setup);
 
-         g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated);
-         if (!paginated)
-           goto out;
-       }
+      g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
 
-      /* Initialize parts of PrintPagesData that depend on nr_of_pages
-       */
-      if (priv->print_pages == GTK_PRINT_PAGES_RANGES)
-       {
-          if (priv->page_ranges == NULL) 
-            {
-              g_warning ("no pages to print");
-              priv->cancelled = TRUE;
-              goto out;
-         }
-         data->ranges = priv->page_ranges;
-         data->num_ranges = priv->num_page_ranges;
-          for (i = 0; i < data->num_ranges; i++)
-            if (data->ranges[i].end == -1 || 
-                data->ranges[i].end >= priv->nr_of_pages)
-              data->ranges[i].end = priv->nr_of_pages - 1;
-       }
-      else if (priv->print_pages == GTK_PRINT_PAGES_CURRENT &&
-              priv->current_page != -1)
-       {
-         data->ranges = &data->one_range;
-         data->num_ranges = 1;
-         data->ranges[0].start = priv->current_page;
-         data->ranges[0].end = priv->current_page;
-       }
+      if (priv->manual_collation)
+        {
+          data->uncollated_copies = priv->manual_num_copies;
+          data->collated_copies = 1;
+        }
       else
-       {
-         data->ranges = &data->one_range;
-         data->num_ranges = 1;
-         data->ranges[0].start = 0;
-         data->ranges[0].end = priv->nr_of_pages - 1;
-       }
-      
-      clamp_page_ranges (data);
+        {
+          data->uncollated_copies = 1;
+          data->collated_copies = priv->manual_num_copies;
+        }
 
-      if (priv->manual_reverse)
-       {
-         data->range = data->num_ranges - 1;
-         data->inc = -1;      
-       }
-      else
-       {
-         data->range = 0;
-         data->inc = 1;      
-       }
-      find_range (data);
-     
-      /* go back one page, since we preincrement below */
-      data->page = data->start - data->inc;
-      data->collated = data->collated_copies - 1;
+      return;
+    }
 
-      _gtk_print_operation_set_status (data->op, 
-                                      GTK_PRINT_STATUS_GENERATING_DATA, 
-                                      NULL);
+  if (g_signal_has_handler_pending (data->op, signals[PAGINATE], 0, FALSE))
+    {
+      gboolean paginated = FALSE;
 
-      goto out;
+      g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated);
+      if (!paginated)
+        return;
     }
 
-  data->total++;
-  data->collated++;
-  if (data->collated == data->collated_copies)
+  /* Initialize parts of PrintPagesData that depend on nr_of_pages
+   */
+  if (priv->print_pages == GTK_PRINT_PAGES_RANGES)
     {
-      data->collated = 0;
-      if (!increment_page_sequence (data))
-       {
-         done = TRUE;
-
-         goto out;
-       }
+      if (priv->page_ranges == NULL) 
+        {
+          g_warning ("no pages to print");
+          priv->cancelled = TRUE;
+          return;
+        }
+      data->ranges = priv->page_ranges;
+      data->num_ranges = priv->num_page_ranges;
+      for (i = 0; i < data->num_ranges; i++)
+        if (data->ranges[i].end == -1 || 
+            data->ranges[i].end >= priv->nr_of_pages)
+          data->ranges[i].end = priv->nr_of_pages - 1;
     }
-  if (data->is_preview && !priv->cancelled)
+  else if (priv->print_pages == GTK_PRINT_PAGES_CURRENT &&
+   priv->current_page != -1)
     {
-      done = TRUE;
-
-      g_signal_emit_by_name (data->op, "ready", priv->print_context);
-      goto out;
+      data->ranges = &data->one_range;
+      data->num_ranges = 1;
+      data->ranges[0].start = priv->current_page;
+      data->ranges[0].end = priv->current_page;
+    }
+  else
+    {
+      data->ranges = &data->one_range;
+      data->num_ranges = 1;
+      data->ranges[0].start = 0;
+      data->ranges[0].end = priv->nr_of_pages - 1;
     }
 
-  common_render_page (data->op, data->page);
-
- out:
+  clamp_page_ranges (data);
 
-  if (priv->cancelled)
+  if (data->num_ranges < 1) 
     {
-      _gtk_print_operation_set_status (data->op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
-      
-      data->is_preview = FALSE;
-      done = TRUE;
+      priv->cancelled = TRUE;
+      return;
     }
 
-  if (done && !data->is_preview)
+  if (priv->manual_reverse)
+    {
+      data->range = data->num_ranges - 1;
+      data->inc = -1;      
+    }
+  else
     {
-      g_signal_emit (data->op, signals[END_PRINT], 0, priv->print_context);
-      priv->end_run (data->op, priv->is_sync, priv->cancelled);
+      data->range = 0;
+      data->inc = 1;      
     }
+  find_range (data);
+
+  /* go back one page, since we preincrement below */
+  data->page = data->start - data->inc;
+  data->collated = data->collated_copies - 1;
+
+  _gtk_print_operation_set_status (data->op, 
+                                   GTK_PRINT_STATUS_GENERATING_DATA, 
+                                   NULL);
+}
+
+static gboolean
+print_pages_idle (gpointer user_data)
+{
+  PrintPagesData *data; 
+  GtkPrintOperationPrivate *priv; 
+  gboolean done = FALSE;
+
+  data = (PrintPagesData*)user_data;
+  priv = data->op->priv;
+
+  if (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_READY)
+    {
+      if (priv->status == GTK_PRINT_STATUS_PREPARING)
+        {
+          prepare_data (data);
+          goto out;
+        }
+
+      data->total++;
+      data->collated++;
+      if (data->collated == data->collated_copies)
+        {
+          data->collated = 0;
+          if (!increment_page_sequence (data))
+            {
+              done = TRUE;
+
+              goto out;
+            }
+        }
+
+      if (data->is_preview && !priv->cancelled)
+        {
+          done = TRUE;
+
+          g_signal_emit_by_name (data->op, "ready", priv->print_context);
+          goto out;
+        }
+
+      common_render_page (data->op, data->page);
 
-  update_progress (data);
+ out:
+
+      if (priv->cancelled)
+        {
+          _gtk_print_operation_set_status (data->op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
+
+          data->is_preview = FALSE;
+          done = TRUE;
+        }
+
+      if (done && !data->is_preview)
+        {
+          g_signal_emit (data->op, signals[END_PRINT], 0, priv->print_context);
+          priv->end_run (data->op, priv->is_sync, priv->cancelled);
+        }
+
+      update_progress (data);
+    }
 
   return !done;
 }
index 38c12d0318b0a8415a48be55935e144269771cdc..a3f04109434f615b3c70cdc14bc50af5abf61868 100644 (file)
@@ -172,6 +172,8 @@ GtkPrintStatus          gtk_print_operation_get_status             (GtkPrintOper
 G_CONST_RETURN gchar *  gtk_print_operation_get_status_string      (GtkPrintOperation  *op);
 gboolean                gtk_print_operation_is_finished            (GtkPrintOperation  *op);
 void                    gtk_print_operation_cancel                 (GtkPrintOperation  *op);
+void                    gtk_print_operation_draw_page_finish       (GtkPrintOperation  *op);
+void                    gtk_print_operation_set_defer_drawing      (GtkPrintOperation  *op);
 
 GtkPageSetup           *gtk_print_run_page_setup_dialog            (GtkWindow          *parent,
                                                                    GtkPageSetup       *page_setup,